package com.kdgc.energy.dmm.result;

import com.kdgc.energy.dmm.Environment;
import com.kdgc.energy.dmm.time.TimeStatistical;
import org.apache.metamodel.data.DataSet;
import org.apache.metamodel.data.Row;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author xu.wenchang
 * @version 1.0 2022/04/24
 */
public class QueryResult {
    
    private String sql;
    
    private DataSet dataSet;
    
    private TimeStatistical timeStatistical;
    
    public QueryResult(TimeStatistical timeStatistical, String sql, DataSet dataSet) {
        this.sql = sql;
        this.dataSet = dataSet;
        this.timeStatistical = timeStatistical;
    }
    
    public <T> List<T> list() {
        if (null == this.dataSet) {
            return null;
        }
        
        this.timeStatistical.phaseStart("build result");
        List<T> list = new ListResult().list(this.dataSet);
        this.statEnd();
        return list;
    }
    
    /**
     * 注意：不支持内部类
     */
    public <T> List<T> list(Class<T> targetClass) {
        if (null == this.dataSet) {
            return null;
        }
        
        this.timeStatistical.phaseStart("build result");
        List<T> list = new ListResult().list(this.dataSet, targetClass);
        this.statEnd();
        return Collections.unmodifiableList(list);
    }
    
    public Map<String, Object> map() {
        if (null == this.dataSet) {
            return null;
        }
        
        this.timeStatistical.phaseStart("build result");
        Map<String, Object> map = new MapResult().map(this.dataSet);
        this.statEnd();
        return Collections.unmodifiableMap(map);
    }
    
    public <T> T one(Class<?> targetClass) {
        if (null == this.dataSet) {
            return null;
        }
        
        this.timeStatistical.phaseStart("build result");
        T t = new SingleResult().one(this.dataSet, targetClass);
        this.statEnd();
        return t;
    }
    
    public <T> T one() {
        if (null == this.dataSet) {
            return null;
        }
        
        this.timeStatistical.phaseStart("build result");
        T result = new SingleResult().one(this.dataSet);
        this.statEnd();
        return result;
    }
    
    public int getInt() {
        return (int) get0(1).orElse(0);
    }
    
    public long getLong() {
        return (long) get0(2).orElse(0L);
    }
    
    public float getFloat() {
        return (float) get0(3).orElse(0F);
    }
    
    public double getDouble() {
        return (double) get0(4).orElse(0D);
    }
    
    private Optional<Object> get0(int type) {
        if (null == this.dataSet) {
            return Optional.empty();
        }
        
        this.timeStatistical.phaseStart("build result");
        if (this.dataSet.next()) {
            Row row = this.dataSet.getRow();
            Object object = row.getValue(0);
            
            if (null != object) {
                this.statEnd();
                
                switch (type) {
                    case 1:
                        return Optional.of(Integer.parseInt(object.toString()));
                    case 2:
                        return Optional.of(Long.parseLong(object.toString()));
                    case 3:
                        return Optional.of(Float.parseFloat(object.toString()));
                    case 4:
                        return Optional.of(Double.parseDouble(object.toString()));
                    default:
                        return Optional.of(object);
                }
            }
        }
        
        this.statEnd();
        return Optional.empty();
    }
    
    protected void statEnd() {
        this.timeStatistical.phaseEnd("build result");
        this.timeStatistical.end();
        if (Environment.isStatExecTime()) {
            this.timeStatistical.setName(this.sql);
            Environment.getWriter()
                       .write(this.timeStatistical.statisticalInfo());
        }
    }
}
